今天我要示範如何渲染一個項目清單。每列還會有一個刪除按鈕,可以從清單中刪除項目。當清單更新後,模板會反應性地重新渲染清單。
新增了一個 Item
類型,所有應用共用。每個項目有 ID
、label
、purchased
,和 higherPriority
:
type Item = {
id: number;
label: string;
purchased: boolean;
higherPriority: boolean;
}
在 ShoppingCart
元件的 <script setup lang="ts">
中,我建立一個 items
的 ref
,給初始值。模板透過 v-for
指令疊代陣列,顯示每個元素。每一列有一個按鈕,尚未綁定事件。事件處理會在後續天數說明。
let items = ref([
{
id: 1,
label: '10 Apples',
purchased: false,
higherPriority: false,
},
{
id: 2,
label: '5 Bananas',
purchased: false,
higherPriority: false,
},
]);
items
是一個反應式陣列,維護購物車的項目列表。當項目被新增或刪除後,清單會自動重新渲染。
<script setup lang="ts">
import { Icon } from "@iconify/vue";
import { ref } from 'vue'
type Item = { ... }
let header = ref('Shopping List App')
let items = ref([...])
</script>
<template>
<h1>{{ header }}</h1>
<ul>
<div class="list-item" v-for="item in items" :key="item.id">
<li>{{ item.id }} - {{ item.label }}</li>
<button class="btn btn-cancel" aria-label="Delete">
<Icon icon="ic:baseline-remove" />
</button>
</div>
</ul>
</template>
v-for
指令用來遍歷 items,顯示每個項目的 ID
與 label
屬性。:key
用來追蹤唯一鍵 id
,避免清單不必要的重新渲染。
刪除按鈕位於清單項目旁邊,並顯示一個移除圖示。這個按鈕目前沒有功能,因為尚未綁定任何事件處理器。
script
標籤中從 iconify/vue
函式庫匯入了 Icon
元件,並用它來顯示移除圖示。
樣式區塊設定為 scoped
,清單項目採用 flex
排版,並在 <li> 元素與按鈕之間加入邊距。
使用 $state
建立反應式陣列 items
,存購物車清單。模板用 #each
語法迭代陣列顯示清單。
let items = $state([
{
id: 1,
label: '10 Apples',
purchased: false,
higherPriority: false,
},
{
id: 2,
label: '5 Bananas',
purchased: false,
higherPriority: false,
},
]);
<script setup lang="ts">
import Icon from "@iconify/svelte";
type Item = { ... }
let header = $state('Shopping List App')
let items = $state([...])
</script>
<template>
<h1>{ header }</h1>
<ul>
{#each items as item (item.id)}
<div class="list-item">
<li>{item.id} - {item.label}</li>
<button class="btn btn-cancel" aria-label="Delete">
<Icon icon="ic:baseline-remove" />
</button>
</div>
{/each}
</ul>
</template>
#each
內建區塊用來遍歷 items
,顯示每個項目的 ID
和 label
屬性。陣列元素的別名為 item
,唯一鍵為 (item.id)
。
刪除按鈕位於清單項目旁邊,並帶有移除圖示。該按鈕目前沒有任何功能,因為尚未綁定事件處理器。
script
標籤中從 iconify/svelte
函式庫匯入了 Icon 元件,並在使用時顯示移除圖示。
style
標籤內的樣式均為作用域樣式。類似地,清單項目採用 flex
排版,並在 <li> 元素與按鈕間加入邊距。
items = signal<Item[]>([
{
id: 1,
label: '10 Apples',
purchased: false,
higherPriority: false,
},
{
id: 2,
label: '5 Bananas',
purchased: false,
higherPriority: false,
},
]);
我宣告了一個帶有初始 Item
陣列的 items
信號(signal)。signal
函式具有泛型 T
,這裡設定為 Item[]
。@for
控制流程語法負責遍歷 items
,並將每個項目顯示在一列中。
@Component({
selector: 'app-shopping-cart',
imports: [NgIcon],
viewProviders: [ provideIcons({ matRemove })],
template: `
<h1>{{ header() }}</h1>
<ul>
@for (item of items(); track item.id) {
<div class="list-item">
<li>{{ item.id }} - {{ item.label }}</li>
<button class="btn btn-cancel" aria-label="Delete">
<ng-icon name="matRemove"></ng-icon>
</button>
</div>
}
</ul>
`,
styles: `
div.list-item {
display: flex;
}
div.list-item > li {
margin-right: 0.5rem;
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
header = signal('Shopping List App');
items = signal<Item[]>([... array element …]);
}
與 Vue 3 和 Svelte 5 不同的是,items
信號是在 ShoppingCartComponent
類別中初始化的。 我在元件的 imports 陣列中引入了 NgIcons
,並在 viewProviders
陣列中使用了 provideIcons({ matRemove })
。ng-icon
指令用來在按鈕上顯示移除圖示。
@for
語法用來遍歷 items
信號,將每個清單項目顯示在列表中。@for
中的 track
表達式是必須的,用來追蹤唯一的鍵 ID
。
此外,Component 裝飾器的 styles
屬性可以用來添加內聯樣式。同樣地,div.list-item
與 div.list-item > li
的內聯樣式會套用到列表和列表項目上。
以上就是今天成功完成的購物車元件清單顯示內容!